import { SceneElement } from './SceneElement';
import { Vector2 } from '../../types/MathTypes';
import { TimelineState } from '../../types/TimelineTypes';

/**
 * UIElement Class
 * 
 * Represents a UI element in the scene, such as dialogue boxes or subtitles.
 */
export class UIElement extends SceneElement {
  private text: string;
  private font: string;
  private fontSize: number;
  private textColor: string;
  private backgroundColor: string;
  private borderColor: string;
  private padding: number;
  private width: number;
  private height: number;
  private textAlign: 'left' | 'center' | 'right';
  private wordWrap: boolean;
  private maxWidth: number;

  /**
   * Creates an instance of UIElement.
   * @param id - Unique identifier
   * @param text - Text content
   * @param position - Position coordinates (x, y)
   * @param font - Font family
   * @param fontSize - Font size in pixels
   * @param textColor - Text color in hex format
   * @param backgroundColor - Background color in hex format
   * @param width - Width of the UI element
   * @param height - Height of the UI element
   * @param scale - Scale factors (x, y)
   * @param rotation - Rotation in degrees
   * @param visible - Visibility flag
   * @param zIndex - Z-order for rendering
   */
  constructor(
    id: string,
    text: string = '',
    position: Vector2 = { x: 0, y: 0 },
    font: string = 'Arial',
    fontSize: number = 16,
    textColor: string = '#000000',
    backgroundColor: string = 'rgba(255, 255, 255, 0.8)',
    width: number = 200,
    height: number = 50,
    scale: Vector2 = { x: 1, y: 1 },
    rotation: number = 0,
    visible: boolean = true,
    zIndex: number = 100 // UI typically has high z-index
  ) {
    super(id, position, scale, rotation, visible, zIndex);
    this.text = text;
    this.font = font;
    this.fontSize = fontSize;
    this.textColor = textColor;
    this.backgroundColor = backgroundColor;
    this.borderColor = '#CCCCCC';
    this.padding = 10;
    this.width = width;
    this.height = height;
    this.textAlign = 'left';
    this.wordWrap = true;
    this.maxWidth = width - 2 * this.padding;
  }

  /**
   * Gets the text content
   * @returns string - The text content
   */
  public getText(): string {
    return this.text;
  }

  /**
   * Sets the text content
   * @param text - The new text content
   */
  public setText(text: string): void {
    this.text = text;
  }

  /**
   * Gets the font family
   * @returns string - The font family
   */
  public getFont(): string {
    return this.font;
  }

  /**
   * Sets the font family
   * @param font - The new font family
   */
  public setFont(font: string): void {
    this.font = font;
  }

  /**
   * Gets the font size
   * @returns number - The font size in pixels
   */
  public getFontSize(): number {
    return this.fontSize;
  }

  /**
   * Sets the font size
   * @param fontSize - The new font size in pixels
   */
  public setFontSize(fontSize: number): void {
    this.fontSize = fontSize;
  }

  /**
   * Gets the text color
   * @returns string - The text color in hex format
   */
  public getTextColor(): string {
    return this.textColor;
  }

  /**
   * Sets the text color
   * @param textColor - The new text color in hex format
   */
  public setTextColor(textColor: string): void {
    this.textColor = textColor;
  }

  /**
   * Gets the background color
   * @returns string - The background color in hex format
   */
  public getBackgroundColor(): string {
    return this.backgroundColor;
  }

  /**
   * Sets the background color
   * @param backgroundColor - The new background color in hex format
   */
  public setBackgroundColor(backgroundColor: string): void {
    this.backgroundColor = backgroundColor;
  }

  /**
   * Gets the border color
   * @returns string - The border color in hex format
   */
  public getBorderColor(): string {
    return this.borderColor;
  }

  /**
   * Sets the border color
   * @param borderColor - The new border color in hex format
   */
  public setBorderColor(borderColor: string): void {
    this.borderColor = borderColor;
  }

  /**
   * Gets the padding
   * @returns number - The padding in pixels
   */
  public getPadding(): number {
    return this.padding;
  }

  /**
   * Sets the padding
   * @param padding - The new padding in pixels
   */
  public setPadding(padding: number): void {
    this.padding = padding;
    this.maxWidth = this.width - 2 * padding;
  }

  /**
   * Gets the width
   * @returns number - The width
   */
  public getWidth(): number {
    return this.width;
  }

  /**
   * Sets the width
   * @param width - The new width
   */
  public setWidth(width: number): void {
    this.width = width;
    this.maxWidth = width - 2 * this.padding;
  }

  /**
   * Gets the height
   * @returns number - The height
   */
  public getHeight(): number {
    return this.height;
  }

  /**
   * Sets the height
   * @param height - The new height
   */
  public setHeight(height: number): void {
    this.height = height;
  }

  /**
   * Gets the text alignment
   * @returns 'left' | 'center' | 'right' - The text alignment
   */
  public getTextAlign(): 'left' | 'center' | 'right' {
    return this.textAlign;
  }

  /**
   * Sets the text alignment
   * @param textAlign - The new text alignment
   */
  public setTextAlign(textAlign: 'left' | 'center' | 'right'): void {
    this.textAlign = textAlign;
  }

  /**
   * Checks if word wrapping is enabled
   * @returns boolean - Word wrapping flag
   */
  public isWordWrap(): boolean {
    return this.wordWrap;
  }

  /**
   * Sets word wrapping
   * @param wordWrap - The new word wrapping flag
   */
  public setWordWrap(wordWrap: boolean): void {
    this.wordWrap = wordWrap;
  }

  /**
   * Wraps text to fit within the specified width
   * @param context - Canvas context for measuring text
   * @param text - Text to wrap
   * @param maxWidth - Maximum width for wrapping
   * @returns string[] - Array of wrapped lines
   */
  private wrapText(context: any, text: string, maxWidth: number): string[] {
    if (!this.wordWrap) {
      return [text];
    }

    const lines: string[] = [];
    const paragraphs = text.split('\n');
    
    for (const paragraph of paragraphs) {
      let line = '';
      const words = paragraph.split(' ');
      
      for (const word of words) {
        const testLine = line + word + ' ';
        const metrics = context.measureText(testLine);
        const testWidth = metrics.width;
        
        if (testWidth > maxWidth && line !== '') {
          lines.push(line);
          line = word + ' ';
        } else {
          line = testLine;
        }
      }
      
      lines.push(line.trim());
    }
    
    return lines;
  }

  /**
   * Renders the UI element
   * @param canvasContext - The canvas context to render to
   */
  public render(canvasContext: any): void {
    console.log(`Rendering UIElement ${this.id}, visible: ${this.visible}`);
    if (!this.visible) {
      console.log(`UIElement ${this.id} is not visible, skipping render`);
      return;
    }

    // Save the current context state
    canvasContext.save();

    try {
      // Apply transformations
      canvasContext.translate(this.position.x, this.position.y);
      canvasContext.rotate(this.rotation * Math.PI / 180);
      canvasContext.scale(this.scale.x, this.scale.y);
      
      console.log(`UIElement ${this.id} transform applied: position=(${this.position.x}, ${this.position.y}), rotation=${this.rotation}, scale=(${this.scale.x}, ${this.scale.y})`);

      // Draw background
      canvasContext.fillStyle = this.backgroundColor;
      canvasContext.fillRect(0, 0, this.width, this.height);
      console.log(`UIElement ${this.id} background drawn with color ${this.backgroundColor}`);

      // Draw border
      canvasContext.strokeStyle = this.borderColor;
      canvasContext.lineWidth = 2;
      canvasContext.strokeRect(0, 0, this.width, this.height);

      // Draw text
      if (this.text) {
        canvasContext.font = `${this.fontSize}px ${this.font}`;
        canvasContext.fillStyle = this.textColor;
        canvasContext.textAlign = this.textAlign;
        canvasContext.textBaseline = 'top';

        // Adjust text position based on alignment
        let textX = this.padding;
        if (this.textAlign === 'center') {
          textX = this.width / 2;
        } else if (this.textAlign === 'right') {
          textX = this.width - this.padding;
        }

        // Wrap text and draw each line
        const lines = this.wrapText(canvasContext, this.text, this.maxWidth);
        const lineHeight = this.fontSize * 1.2;
        const totalHeight = lines.length * lineHeight;
        const startY = (this.height - totalHeight) / 2;

        for (let i = 0; i < lines.length; i++) {
          const line = lines[i];
          const y = startY + i * lineHeight;
          canvasContext.fillText(line, textX, y);
        }
        
        console.log(`UIElement ${this.id} text drawn: "${this.text}"`);
      }
    } finally {
      // Restore the context state
      canvasContext.restore();
      console.log(`UIElement ${this.id} render completed`);
    }
  }

  /**
   * Updates the element based on timeline state
   * @param timelineState - The current timeline state
   */
  public update(timelineState: TimelineState): void {
    // Handle UI-specific updates based on timeline state
    const uiTrack = timelineState.tracks[this.id];
    if (uiTrack) {
      if (uiTrack.text !== undefined) {
        this.setText(uiTrack.text);
      }
      
      if (uiTrack.visible !== undefined) {
        this.setVisible(uiTrack.visible);
      }
      
      if (uiTrack.position) {
        this.setPosition(uiTrack.position);
      }
      
      if (uiTrack.fontSize) {
        this.setFontSize(uiTrack.fontSize);
      }
      
      if (uiTrack.textColor) {
        this.setTextColor(uiTrack.textColor);
      }
      
      if (uiTrack.backgroundColor) {
        this.setBackgroundColor(uiTrack.backgroundColor);
      }
    }
  }
}